#include <unistd.h>
#include <string.h>
#include <stdlib.h>

#include "auth.h"
#include "error_code.h"
#include "parser.h"
#include "command.h"
#include "base.h"
#include "fcgi_stdio.h"

int
parser_cmd_param(ParserStruc *pstruc, const char *cmdkey, char *value, int value_size)
{
    //char *pvalue = value;

    if (NULL == pstruc) {
        DERROR("pstruc is null\n");
        return -1;
    }
    char *ptr;
    ptr = pstruc->query_string;
    if (*ptr == '\0') {
        DERROR("query_string is null\n");
        return -2;
    }
    DINFO("query_string: %s\n", pstruc->query_string);

    char *cmd;
    /*if (NULL == cmd) {
        DERROR("can't find cmd string in query_string: %s\n", ptr);
        return -3;
    }*/
	char key[100];
	snprintf(key, 100, "%s=", cmdkey);
    cmd = strstr(ptr, key);

    if (NULL == cmd) {
        DERROR("can't find %s in query_string: %s\n", key, ptr);
        return -4;
    }
    cmd += strlen(key); 
    if (*cmd == '\0') {
        DERROR("%s have no value in query_string: %s\n", cmdkey, ptr);
        return -6;
    }

    char *start = value;
    int len = 0;

    while (len < value_size - 1) {
        if (*cmd == '&' || *cmd == '\0')
            break;
        *start++ = *cmd++;
        len++;
    }
    *start = '\0';
    
    return 0;
}

int parser_cmd_recover_param(ParserStruc *pstruc, int& type)
{
    int ret;
    char buf[16];
    ret = parser_cmd_param(pstruc, "type", buf, 16);
    if (ret < 0)
    {
        return ret;
    }
    else
    {
        int len = sscanf(buf, "%d", &type);
        if (len != 1)
        {
            return ERROR_CODE_ILLEGAL_ARGUMENT;
        }
    }
    
    return 0;
}

int parser_cmd_lsdir_param(ParserStruc *pstruc, int& mode)
{
    int ret;
    char buf[16];
    ret = parser_cmd_param(pstruc, "mode", buf, 16);
    if (ret < 0)
    {
        return ret;
    }
    else
    {
        int len = sscanf(buf, "%d", &mode);
        if (len != 1)
        {
            return ERROR_CODE_ILLEGAL_ARGUMENT;
        }
    }
    
    return 0;
}

int parser_cmd_readfile_param(ParserStruc *pstruc, uint32_t& version, uint32_t& offset, uint32_t& length)
{
    int ret;
    char buf[128];
    
    ret = parser_cmd_param(pstruc, "version", buf, 128);
    if (ret < 0)
    {
        version = (uint32_t)-1;
    }
    else
    {
        int len = sscanf(buf, "%u", &version);
        if (len != 1)
        {
            return ERROR_CODE_ILLEGAL_ARGUMENT;
        }
    }
    
    ret = parser_cmd_param(pstruc, "offset", buf, 128);
    if (ret < 0)
    {
        offset = 0;
    }
    else
    {
        int len = sscanf(buf, "%u", &offset);
        if (len != 1)
        {
            return ERROR_CODE_ILLEGAL_ARGUMENT;
        }
    }
    
    ret = parser_cmd_param(pstruc, "length", buf, 128);
    if (ret < 0)
    {
        length = (uint32_t)-1;
    }
    else
    {    
        int len = sscanf(buf, "%u", &length);
        if (len != 1)
        {
            return ERROR_CODE_ILLEGAL_ARGUMENT;
        }
    }
    
    return 0;    
}

int
parser_storage_cmd(ParserStruc *pstruc)
{
    //http://domain/storage/cmd?parameter
    //new interface
    // http://domain/userid/parentid/cmd?parameter
    if (NULL == pstruc) {
        DERROR("pstruc NULL, error\n");
        return -1;
    }

    char *ptr = pstruc->script_name;
    //int  size = strlen(pstruc->script_name);

    if (*ptr == '\0') {
        DERROR("script_name is NULL\n");
        return -2;
    }
    
    DINFO("ptr: %s\n", ptr);
    
    if (*ptr == '/')
    {
        ptr++;
        if (NULL == ptr) {
            DERROR("can't  find next / in script_name, script_name: %s\n", pstruc->script_name);
            return - 6;
        }
        //copy userid
        char buf[128];
        char* sbuf = buf;
        
        char *end = strchr(ptr, '/');
        if (NULL == end) {
            DERROR("can't find next / in stript_name: %s\n", pstruc->script_name);
            return -7;
        }
        while(ptr != end) {
            *sbuf++ = *ptr++; 
        }
        *sbuf = '\0';
        
        pstruc->_parentid._parts._userID = atoi(buf);
        
        //copy parentid
        sbuf = buf;
        ptr ++;
        end = strchr(ptr, '/');        
        if (NULL == end) {
            DERROR("can't find next / in stript_name: %s\n", pstruc->script_name);
            return -7;
        }
        while(ptr != end) {
            *sbuf++ = *ptr++; 
        }
        *sbuf = '\0';
        
        pstruc->_parentid._parts._dirSN = atoi(buf);
        
        //copy cmd
        ptr++;
        if (*ptr == '\0') {
            DERROR("can't find cmd in url: %s\n", pstruc->script_name);
            return -8;
        }
        if (*ptr != '\0') {
            if (strncasecmp(ptr, "mkdir", strlen("mkdir")) == 0) {
                pstruc->cmd = CMD_MKDIR;
            } else if (strncasecmp(ptr, "lsdir", strlen("lsdir")) == 0) {
                pstruc->cmd = CMD_LSDIR;
            } else if (strncasecmp(ptr, "rmdir", strlen("rmdir")) == 0) {
                pstruc->cmd = CMD_RMDIR;
            } else if (strncasecmp(ptr, "rename_dir", strlen("rename_dir")) == 0) {
                pstruc->cmd = CMD_RENAME_DIR;
            } else if (strncasecmp(ptr, "writefile", strlen("writefile")) == 0) {
                pstruc->cmd = CMD_WRITEFILE;
            } else if (strncasecmp(ptr, "readfile", strlen("readfile")) == 0) {
                pstruc->cmd = CMD_READFILE;
            } else if (strncasecmp(ptr, "rmfile", strlen("rmfile")) == 0) {
                pstruc->cmd = CMD_RMFILE;   
            } else if (strncasecmp(ptr, "rename_file", strlen("rename_file")) == 0) {
                pstruc->cmd = CMD_RENAME_FILE;
            } else if (strncasecmp(ptr, "recover", strlen("recover")) == 0) {
                pstruc->cmd = CMD_RECOVER;
            } else if (strncasecmp(ptr, "dirinfo", strlen("dirinfo")) == 0) {
                pstruc->cmd = CMD_DIR_INFO;
            } else if (strncasecmp(ptr, "fileinfo", strlen("fileinfo")) == 0) {
                pstruc->cmd = CMD_FILE_INFO;
            } else if (strncasecmp(ptr, "fileversion", strlen("fileversion")) == 0) {
                pstruc->cmd = CMD_FILE_VERSION;
            } else
            {
                pstruc->cmd = CMD_UNKNOWN;
            }
        }
    }
    
    // parse normal parameter
    parser_cmd_param(pstruc, "name", pstruc->_name, MAX_FILENAME);
    
    parser_cmd_param(pstruc, "newname", pstruc->_newname, MAX_FILENAME);
    
    DNOTE("Receive CMD:%d, userid:%u, parentid:%u, name:%s",
          pstruc->cmd, pstruc->_parentid._parts._userID, pstruc->_parentid._parts._dirSN, pstruc->_name);
    return 0;
}

int 
parser_requ_env(FCGX_Request *request, ParserStruc *pstruc)
{
    //char **envp = environ;
    //char line[1024];
	char *env_str;
    
	env_str = FCGX_GetParam("REMOTE_ADDR", request->envp);
	if (env_str) {
	/*
        if (!auth_valid(env_str)) {
			DERROR("%s authentication faild\n", env_str);
			return ERROR_CODE_AUTH;
		}
     */
	} else {
		DERROR("authentication info is empty\n");
		return ERROR_CODE_AUTH;
	}

	env_str = FCGX_GetParam("QUERY_STRING", request->envp);
	if (env_str) {
		snprintf(pstruc->query_string, 1024, "%s", env_str); 
        DINFO("query_string: %s\n", env_str);
	}

	env_str = FCGX_GetParam("SCRIPT_NAME", request->envp);
	if (env_str) {
		snprintf(pstruc->script_name, 1024, "%s", env_str); 
        DINFO("script name: %s\n", env_str);
	}

	env_str = FCGX_GetParam("CONTENT_LENGTH", request->envp);
	if (env_str) {
		pstruc->content_length = atoi(env_str);
		int size = pstruc->content_length+1;
		char ch;
		int i;
		pstruc->content = (char *)zz_malloc(size);
		memset(pstruc->content, 0x0, size);
		for (i = 0; i < pstruc->content_length; i++) {
			ch = FCGX_GetChar(request->in);
			/*
            if (ch == EOF) {
				DINFO("getchar eof: %d\n", i);
				break;
			}
             */
			pstruc->content[i] = ch;
			//DINFO("-----------%d\n", ch);
		}
		pstruc->content[i] = '\0';
	}

/*
    for (; *envp != NULL; envp++) {
        snprintf(line, 1024, "%s", *envp);
        DINFO("====line: %s\n", line);
        if (strncmp(line, "QUERY_STRING", strlen("QUERY_STRING")) == 0) {
            snprintf(pstruc->query_string, 1024, "%s", line); 
        }
        if (strncmp(line, "SCRIPT_NAME", strlen("SCRIPT_NAME")) == 0) {
            snprintf(pstruc->script_name, 1024, "%s", line);
        }
        if (strncmp(line, "CONTENT_LENGTH", strlen("CONTENT_LENGTH")) == 0) {
            char *ptr;
            
            ptr = strchr(line, '=');
            if (ptr == NULL) {
                pstruc->content_length = 0;
            }
            else {
                ptr++;
                if (*ptr == '\0') {
                    DNOTE("not have content lenght\n");
                    continue;
                }
                pstruc->content_length = atoi(ptr);
                int size = pstruc->content_length;
                char ch;
                int i;
                pstruc->content = (char *)zz_malloc(size+1);
                memset(pstruc->content, 0x0, size);
                for (i = 0; i < pstruc->content_length; i++) {
					if (FCGI_feof(FCGI_stdout)) {
						DINFO("getchar eof: %d\n", i);
						break;
					}
                    ch = FCGI_getchar();
					pstruc->content[i] = ch;
					//DINFO("-----------%d\n", ch);
                }
				pstruc->content[size] = '\0';
            }
        }
    }
*/
    return 0;
}

ParserStruc*
parser_init()
{
    ParserStruc *pstruc = NULL;

    pstruc = (ParserStruc *)zz_malloc(sizeof(ParserStruc));
    memset(pstruc, 0x0, sizeof(ParserStruc));
    return pstruc;
}

void
parser_destroy(ParserStruc *pstruc)
{
    if (pstruc == NULL)
        return;

    if (pstruc->content)
        zz_free(pstruc->content);

    zz_free(pstruc);
}

